package io.gitee.mingbaobaba.security.quickstart.endpoint;

import io.gitee.mingbaobaba.security.core.annotion.SecurityIgnore;
import io.gitee.mingbaobaba.security.core.constants.ErrorCodeConstant;
import io.gitee.mingbaobaba.security.core.constants.SecurityConstant;
import io.gitee.mingbaobaba.security.core.context.SecurityContext;
import io.gitee.mingbaobaba.security.core.domain.SecurityLoginParams;
import io.gitee.mingbaobaba.security.core.domain.SecurityUserDetails;
import io.gitee.mingbaobaba.security.core.exception.SecurityBaseException;
import io.gitee.mingbaobaba.security.core.exception.SecurityBusinessException;
import io.gitee.mingbaobaba.security.core.factory.SecurityFactory;
import io.gitee.mingbaobaba.security.core.response.SecurityResponseWrapper;
import io.gitee.mingbaobaba.security.core.utils.SecurityUtil;
import io.gitee.mingbaobaba.security.quickstart.SecurityQuickManager;
import io.gitee.mingbaobaba.security.quickstart.utils.TicketUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.Objects;

/**
 * <p>快速启动controller</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/9/6 10:24
 */
@Controller
@Slf4j
public class QuickstartEndpoint {

    /**
     * 登录页
     *
     * @param model Model
     * @return String
     */
    @SecurityIgnore
    @GetMapping({"/securityLogin"})
    public ModelAndView securityLogin(ModelAndView model) {
        setSecurityLoginModelAndView(model);
        return model;
    }

    /**
     * 登录方法
     *
     * @param username 用户名
     * @param password 密码
     * @return String
     */
    @SecurityIgnore
    @PostMapping({"/securityLogin"})
    public ModelAndView securityLogin(@RequestParam("username") String username,
                                      @RequestParam("password") String password, ModelAndView model) {
        //获取请求参数中是否携带redirect_url参数，如果携带redirect_url则直接跳转到redirect_url
        String url = SecurityFactory.getSecurityRequest.get().getParameter(SecurityConstant.REDIRECT_URL);
        try {
            doLogin(username, password);
            if (StringUtils.isBlank(url)) {
                if (StringUtils.isNoneBlank(SecurityFactory.getConfig.get().getLoginConfig().getSuccessPage())) {
                    //跳转第三方生成一个ticket，可根据ticket换取token信息
                    String ticket = TicketUtil.generateTicket(SecurityUtil.getCurrentTokenValue(),
                            SecurityQuickManager.getConfig().getTicketTimeOut());
                    url = SecurityFactory.getConfig.get().getLoginConfig().getSuccessPage() +
                            (SecurityFactory.getConfig.get().getLoginConfig()
                                    .getSuccessPage().contains("?") ? "&" : "?") + "ticket=" + ticket;
                } else {
                    //跳转到默认登录成功页面
                    url = "/securityLoginSuccess";
                }
            }
            model.setViewName("redirect:" + url);
            return model;

        } catch (SecurityBaseException e) {
            log.error("错误码：{},错误描述:{}", e.getCode(), e.getMessage());
            setSecurityLoginModelAndView(model);
            //错误信息
            model.getModel().put("errorMsg", e.getMessage());
            return model;
        }
    }

    /**
     * 登录方法
     *
     * @param username 用户名
     * @param password 密码
     * @return 包装对象
     */
    @SecurityIgnore
    @PostMapping({"/doSecurityLogin"})
    @ResponseBody
    public Object securityLogin(@RequestParam("username") String username,
                                @RequestParam("password") String password) {
        SecurityResponseWrapper wrapper = SecurityFactory.getSecurityResponseWrapper.get();
        try {
            doLogin(username, password);
            return wrapper.wrapper(SecurityUtil.getCurrentToken(), false, null);
        } catch (SecurityBaseException e) {
            log.error("错误码：{},错误描述:{}", e.getCode(), e.getMessage());
            return wrapper.wrapper(null, true, e);
        }
    }

    /**
     * 登录操作
     *
     * @param username 用户名
     * @param password 密码
     */
    private void doLogin(String username, String password) {
        if (SecurityFactory.getConfig.get().getLoginConfig().isDisabled()) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_DISABLED_LOGIN, "登录操作被禁用");
        }
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_PARAMS, "用户名或密码不能为空");
        }

        SecurityContext securityContext = SecurityFactory.getSecurityContext.get();
        SecurityLoginParams loginParams = new SecurityLoginParams();
        if (Boolean.FALSE.equals(SecurityFactory.getSecurityUserDetailsService.get()
                .preHandle(username, loginParams, securityContext))) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_DISABLED_LOGIN, "登录操作被限制");
        }

        //是否开启验证码功能
        if (Boolean.TRUE.equals(SecurityFactory.getConfig.get().getLoginConfig().isCaptchaEnabled())) {
            //验证码流水Id
            String captchaSeqId = securityContext.securityRequest().getParameterNonNull("captchaSeqId");
            //验证码
            String code = securityContext.securityRequest().getParameterNonNull("code");
            if (Boolean.FALSE.equals(SecurityFactory.getSecurityCaptchaRepository.get().validCaptcha(captchaSeqId, code))) {
                throw new SecurityBusinessException(ErrorCodeConstant.CODE_CAPTCHA_ERR, "验证码错误");
            }
        }

        SecurityUserDetails userDetails = SecurityFactory.getSecurityUserDetailsService.get()
                .findSecurityUserDetailsByUsername(username);
        if (Objects.isNull(userDetails) || StringUtils.isBlank(userDetails.getLoginId())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_NO_EXIST_USER, "登录用户不存在");
        }
        if (StringUtils.isBlank(userDetails.getPassword()) ||
                !userDetails.getPassword().equals(SecurityFactory.getSecurityUserDetailsService.get()
                        .passwordPolicy(password, userDetails, securityContext))) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_PASSWORD_ERR, "登录密码错误");
        }

        //登录操作
        SecurityUtil.doLogin(userDetails.getLoginId(), loginParams);
        SecurityFactory.getSecurityUserDetailsService.get().afterCompletion();
    }

    /**
     * 设置登录页面信息
     *
     * @param model ModelAndView
     */
    private void setSecurityLoginModelAndView(ModelAndView model) {
        //跳转参数
        model.getModel().put(SecurityConstant.REDIRECT_URL, SecurityFactory.getSecurityRequest.get().getParameter(SecurityConstant.REDIRECT_URL));
        //登录标题
        model.getModel().put("loginTitle", SecurityFactory.getConfig.get().getLoginConfig().getLoginTitle());
        //版权信息
        model.getModel().put("copyright", SecurityFactory.getConfig.get().getLoginConfig().getCopyright());
        //跳转登录页
        model.setViewName("login.html");
    }

    /**
     * 根据ticket查询token
     *
     * @param ticket 凭证
     * @return token
     */
    @SecurityIgnore
    @PostMapping({"/getTokenByTicket"})
    @ResponseBody
    public Object getTokenByTicket(@RequestParam("ticket") String ticket) {
        SecurityResponseWrapper responseWrapper = SecurityFactory.getSecurityResponseWrapper.get();
        String token;
        try {
            token = TicketUtil.parseTicket(ticket);
        } catch (Exception e) {
            log.error("解析凭证异常,异常原因:{}，异常码：{}", e.getMessage(), ErrorCodeConstant.CODE_PARSE_TICKET_ERR);
            return responseWrapper.wrapper(e.getMessage(), true,
                    new SecurityBusinessException(ErrorCodeConstant.CODE_PARSE_TICKET_ERR, "解析凭证异常"));
        }
        return responseWrapper.wrapper(token, false, null);
    }

    /**
     * 登录成功跳转页
     *
     * @param model Model
     * @return String
     */
    @GetMapping({"/securityLoginSuccess"})
    public String securityLoginSuccess(Model model) {
        //跳转成功页
        return "success.html";
    }

}
